package logic

import (
	"fmt"

	"github.com/go-programing-tour-book/chatroom/global"
)

// 单例：广播器
var BroadCaster = &broadcaster{
	users: make(map[string]*User),

	enteringChannel: make(chan *User),
	leavingChannel:  make(chan *User),
	messageChannel:  make(chan *Message, global.MessageQueueLen),

	checkUserChannel:      make(chan string),
	checkUserCanInChannel: make(chan bool),

	requestUsersChannel: make(chan struct{}),
	UsersChannel:        make(chan []*User),
}

// 广播器
type broadcaster struct {
	//聊天室所有用户
	users map[string]*User

	//所有channel同一管理，可以避免外部乱用
	enteringChannel chan *User
	leavingChannel  chan *User
	messageChannel  chan *Message

	//判断该昵称用户是否可进入聊天室(重复与否)：true能 false 不能
	checkUserChannel      chan string
	checkUserCanInChannel chan bool

	requestUsersChannel chan struct{}
	UsersChannel        chan []*User
}

func (b *broadcaster) Start() {
	for {
		select {
		case user := <-b.enteringChannel:
			b.users[user.NickName] = user
			fmt.Println(user.NickName, len(b.users))
			GetOfflineProcessor().Send(user)
		case user := <-b.leavingChannel:
			delete(b.users, user.NickName)
			//避免goroutine泄露
			user.CloseMessageChannel()
		case msg := <-b.messageChannel:
			//给所有在线用户发送消息
			for _, user := range b.users {
				if msg.User != nil && user.UID == msg.User.UID {
					continue
				}
				user.messageChannel <- msg
			}
			GetOfflineProcessor().Save(msg)
		case nickname := <-b.checkUserChannel:
			if _, ok := b.users[nickname]; ok {
				b.checkUserCanInChannel <- false
			} else {
				b.checkUserCanInChannel <- true
			}

		case <-b.requestUsersChannel:
			var userlist = make([]*User, 0, len(b.users))
			for _, user := range b.users {
				userlist = append(userlist, user)
			}
			b.UsersChannel <- userlist
		}
	}
}

func (b *broadcaster) UserEntering(u *User) {
	b.enteringChannel <- u
}

func (b *broadcaster) UserLeaving(u *User) {
	b.leavingChannel <- u
}

func (b *broadcaster) Broadcast(msg *Message) {
	b.messageChannel <- msg
}

func (b *broadcaster) CanEnterRoom(nickname string) bool {
	b.checkUserChannel <- nickname
	return <-b.checkUserCanInChannel
}

func (b *broadcaster) GetUserList() []*User {
	b.requestUsersChannel <- struct{}{}
	return <-b.UsersChannel
}
